package de.lmu.ifi.pst.uwejsf.framework;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.beanutils.PropertyUtils;

import de.lmu.ifi.pst.uwejsf.framework.process.ProcessDataflowException;

public class UWEScriptHelper {
	private ExpressionContextProvider contextProvider;

	public UWEScriptHelper(ExpressionContextProvider contextProvider) {
		this.contextProvider = contextProvider;
	}

	public String type(Object obj) {
		return contextProvider.getTypeMapping(obj.getClass().getName());
	}

	public Object create(String typeName) {
		String applicationClassName = contextProvider
				.getReverseTypeMapping(typeName);
		// if we can't find it in the type mapping, try to load the class
		// directly
		if (applicationClassName == null)
			applicationClassName = typeName;
		Object newInstance = null;
		Class<?> applicationClass = null;

		try {
			applicationClass = Class.forName(applicationClassName);
		} catch (ClassNotFoundException e) {
			throw new ExpressionContentException("Couldn't find class "
					+ typeName + ".");
		}

		Constructor<?> constructor = null;
		try {
			constructor = applicationClass.getConstructor(new Class<?>[0]);
			newInstance = constructor.newInstance();
		} catch (Exception e) {
			throw new ExpressionContentException(
					"Couldn't access default constructor of class " + typeName
							+ ".");
		}
		return newInstance;

	}

	public Map<String, Object> prefixExplode(Object bean, String prefix) {
		Map<String, Object> result = new HashMap<String, Object>();
		if (bean == null)
			return result;

		PropertyDescriptor[] descriptors = PropertyUtils
				.getPropertyDescriptors(bean);
		for (PropertyDescriptor pd : descriptors) {
			if (PropertyUtils.isReadable(bean, pd.getName())) {
				Object value = null;
				try {
					value = PropertyUtils.getProperty(bean, pd.getName());
				} catch (Exception e) {
					throw new UWEJSFRuntimeException(
							"Can't access bean property " + pd.getName() + ".",
							e);

				}

				String pName = prefix.endsWith("_") ? pName = prefix.concat(pd
						.getName()) : prefix.concat(UWEHelpers.firstToUpper(pd
						.getName()));
				result.put(pName, value);

			}
		}
		return result;

	}

	public Map<String, Object> filterPrefix(Map<String, Object> inMap,
			String prefix) {
		Map<String, Object> result = new HashMap<String, Object>();
		for (String key : inMap.keySet()) {
			if (key.startsWith(prefix))
				result.put(UWEHelpers.firstToLower(key.substring(prefix
						.length())), inMap.get(key));
		}
		return result;
	}

	public Object update(Object target, Map<String, Object> parameters) {
		if (target == null) return null;
		for (String key : parameters.keySet()) {
			if (PropertyUtils.isWriteable(target, key)) {
				try {
					PropertyUtils.setProperty(target, key, parameters.get(key));
				} catch (Exception e) {
					throw new ProcessDataflowException(
							"Couldn't access property " + key + " of object "
									+ target.toString(), e);
				}
			}

		}
		return target;
	}

}